
#pragma once
#include <memory>
#include <atomic>
#include <vector>
#include <boost/asio/experimental/channel.hpp>
#include <boost/asio/experimental/concurrent_channel.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/buffer.hpp>

#include "core/session.hpp"
#include "core/stream_session.hpp"
#include "base/utils/utils.h"

namespace mms {
    class HttpRequest;
    class HttpResponse;
    class FlvMediaSink;
    class FlvTag;
    class MediaEvent;

    class HttpFlvServerSession : public StreamSession {
    public:
        HttpFlvServerSession(std::shared_ptr<HttpRequest> http_req, std::shared_ptr<HttpResponse> http_resp);
        virtual ~HttpFlvServerSession();
        void service();
        void close(bool close_connection);
        void close();
    private:
        boost::asio::awaitable<bool> send_flv_tags(std::vector<std::shared_ptr<FlvTag>> tags);

        void start_send_coroutine();
        boost::asio::awaitable<void> stop_send_coroutine();

        void start_alive_checker();
        void update_active_timestamp();
        boost::asio::awaitable<void> stop_alive_checker();
    private:
        std::shared_ptr<FlvMediaSink> flv_media_sink_;

        std::shared_ptr<HttpRequest> http_request_;
        std::shared_ptr<HttpResponse> http_response_;

        boost::asio::experimental::channel<void(boost::system::error_code, std::function<boost::asio::awaitable<bool>()>)> send_funcs_channel_;

        std::vector<boost::asio::const_buffer> send_bufs_;
        uint32_t prev_tag_size_ = 0;
        std::atomic_flag closed_ = ATOMIC_FLAG_INIT;

        bool recv_coroutine_running_ = false;
        bool send_coroutine_running_ = false;
        boost::asio::experimental::concurrent_channel<void(boost::system::error_code, bool)> recv_coroutine_exited_;
        boost::asio::experimental::concurrent_channel<void(boost::system::error_code, bool)> send_coroutine_exited_;

        int64_t last_active_time_ = Utils::get_current_ms();
        bool alive_checker_coroutine_running_ = false;
        boost::asio::steady_timer alive_timeout_timer_;//超时定时器，如果超过一段时间，没有任何数据，则关闭session 
        boost::asio::experimental::concurrent_channel<void(boost::system::error_code, bool)> alive_checker_coroutine_exited_;

        int32_t prev_tag_sizes_[1024];
    };

};